﻿using System;
using System.Collections.Generic;
using System.Linq;
using Application.Interfaces;
using Domain.Common;
using Domain.Setup.Skills;
using Domain.Setup.Tasks;

namespace Application.Setup
{
    /// <summary>
    /// Coordinates the interactions of the domain and domain repositories for the purpose of executing business
    /// functions in the System Setup domain
    /// </summary>
    public class SetupManagementService : ISetupManagementService
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SetupManagementService"/> class.
        /// </summary>
        /// <param name="skillRepository">The skill repository.</param>
        /// <param name="taskRepository">The task repository.</param>
        /// <param name="unitOfWork">The unit of work.</param>
        /// <param name="setupDomainService">The setup domain service.</param>
        public SetupManagementService(ISkillRepository skillRepository, ITaskRepository taskRepository, IUnitOfWork unitOfWork, ISetupSkillDomainService setupDomainService)
        {
            // Keep local references to dependencies
            if (skillRepository == null)
            {
                throw new ArgumentException("A valid SkillRepository is required for this Application Service.");
            }
            if (taskRepository == null)
            {
                throw new ArgumentException("A valid TaskRepository is required for this Application Service.");
            }
            if (taskRepository == null)
            {
                throw new ArgumentException("A valid SkillsDomainService is required for this Application Service.");
            }
            if (unitOfWork == null)
            {
                throw new ArgumentException("A valid Unit of work is required for this Application Service");
            }

            this.SkillRepository = skillRepository;
            this.SetupDomainService = setupDomainService;
            this.TaskRepository = taskRepository;
            this.UnitOfWork = unitOfWork;
        }

        #region Public Properties
        /// <summary>
        /// Gets the skill repository used Skills.
        /// </summary>
        public ISkillRepository SkillRepository { get; private set; }

        /// <summary>
        /// Gets the task repository used to update Tasks. 
        /// </summary>
        public ITaskRepository TaskRepository { get; private set; }

        /// <summary>
        /// Gets the unit of work used to commit or rollback work.
        /// </summary>
        public IUnitOfWork UnitOfWork { get; private set; }

        /// <summary>
        /// Gets the setup domain service used.
        /// </summary>
        public ISetupSkillDomainService SetupDomainService { get; private set; } 
        #endregion

        /// <summary>
        /// Gets all the skills from storage.
        /// </summary>
        /// <returns></returns>
        public List<Domain.Setup.Entities.Skill> GetAllSkills()
        {
            return SkillRepository.Get().ToList();
        }

        /// <summary>
        /// Adds a skill to storage.
        /// </summary>
        /// <param name="skill">The skill.</param>
        /// <returns></returns>
        public Domain.Setup.Entities.Skill AddSkill(Domain.Setup.Entities.Skill skill)
        {
            var item = SkillRepository.Add(skill);

            UnitOfWork.Save();

            return item;
        }

        /// <summary>
        /// Updates the specifed skill in storage.
        /// </summary>
        /// <param name="skill">The skill.</param>
        public void UpdateSkill(Domain.Setup.Entities.Skill skill)
        {
            SkillRepository.Update(skill);

            UnitOfWork.Save();
        }

        /// <summary>
        /// Deletes the specified skill from storage.
        /// </summary>
        /// <param name="skill">The skill.</param>
        public void DeleteSkill(Domain.Setup.Entities.Skill skill)
        {
            SetupDomainService.DeleteSkill(skill);
            UnitOfWork.Save();
        }

        /// <summary>
        /// Gets all tasks for skill specified from storage.
        /// </summary>
        /// <param name="skill">The skill.</param>
        /// <returns></returns>
        public List<Domain.Setup.Entities.Task> GetAllTasksForSkill(Domain.Setup.Entities.Skill skill)
        {
            return TaskRepository.Get(x => x.RequiredSkill.Id == skill.Id).ToList();
        }

        /// <summary>
        /// Adds the specified task to storage.
        /// </summary>
        /// <param name="task">The task.</param>
        /// <param name="skillId">The skill id.</param>
        /// <returns></returns>
        public Domain.Setup.Entities.Task AddTask(Domain.Setup.Entities.Task task, int skillId)
        {
            var item = SetupDomainService.AddTask(task, skillId);

            UnitOfWork.Save();

            return item;
        }

        /// <summary>
        /// Updates the specified task in storage.
        /// </summary>
        /// <param name="task">The task.</param>
        public void UpdateTask(Domain.Setup.Entities.Task task)
        {
            TaskRepository.Update(task);

            UnitOfWork.Save();
        }

        /// <summary>
        /// Deletes the specified task from storage.
        /// </summary>
        /// <param name="task">The task.</param>
        public void DeleteTask(Domain.Setup.Entities.Task task)
        {
            TaskRepository.Delete(task);

            UnitOfWork.Save();
        }
    }
}
